﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Com.Guocz.Media.FileSystem;
using System.Threading;

namespace BVision
{
    public partial class FrmMain : Form
    {
        private FrmMainLogic logic = new FrmMainLogic();
        private Model model = new Model();
        Semaphore sem = new Semaphore(0, 1);
        Mutex operMutex = new Mutex();
        delegate void doReload(Model model);

        public FrmMain()
        {
            InitializeComponent();
            menuStat();
        }

        void menuStat()
        {
            bool enable = model.FS != null;
            this.fileAdd.Enabled = enable;
            this.fileDelete.Enabled = enable;
            this.fileMkdir.Enabled = enable;
            this.fileDelF.Enabled = enable;
            this.filePre.Enabled = enable;
            this.fileNext.Enabled = enable;
            this.fileRotate.Enabled = enable;
            this.mnImport.Enabled = enable;
            this.mnExport.Enabled = enable;

            this.mnExport.Visible = false;
            this.mnImport.Visible = false;

            this.prgStatus.Visible = false;
            this.lblStatus.Visible = false;
        }

        private void reloadTree(Model model)
        {
            this.tvFolder.BeginUpdate();
            this.tvFolder.Nodes.Clear();
            this.tvFolder.Nodes.Add(getNode(model.Root));
            this.tvFolder.EndUpdate();
        }

        private TreeNode getNode(Com.Guocz.Media.FileSystem.Path dir)
        {
            TreeNode root = new TreeNode(dir.Name);
            root.Tag = dir;
            if (dir.Tag)
            {
                root.Expand();
            }

            if (string.IsNullOrEmpty(root.Text)) //must be root
            {
                root.Text = "ROOT";
                root.ImageIndex = 0;
                root.SelectedImageIndex = 0;
                root.Expand();
            }
            else if (dir.IsDirectory)
            {
                root.ImageIndex = 1;
                root.SelectedImageIndex = 1;
            }
            else
            {
                root.ImageIndex = 2;
                root.SelectedImageIndex = 2;
            }
            
            
            foreach (var subdir in dir.Children)
            {
                if (subdir.IsDirectory)
                {
                    root.Nodes.Add(getNode(subdir));
                }
            }
            foreach (var subfile in dir.Children)
            {
                if (!subfile.IsDirectory)
                {
                    TreeNode node = new TreeNode(subfile.Name);
                    node.Tag = subfile;
                    root.Nodes.Add(node);
                    node.ImageIndex = 2;
                    node.SelectedImageIndex = 2;
                }
            }

            return root;
        }

        private void fsNew_Click(object sender, EventArgs e)
        {
            DlgMain createDlg = new DlgMain();
            createDlg.Create = true;
            if (createDlg.ShowDialog() == DialogResult.OK)
            {
                model.FS = logic.create(createDlg.User, createDlg.Pass, createDlg.Path);
                reloadAll(model);
            }
        }

        private void fileMkdir_Click(object sender, EventArgs e)
        {
            DlgInput input = new DlgInput();
            if (input.ShowDialog() == DialogResult.OK)
            {
                logic.mkdir(model, input.InputText);
                reloadAll(model); 
            }
        }

        private void reloadAll(Model model)
        {
            menuStat();
            reloadTree(model);
            reloadListView(model);
            reloadViewer();
        }

        private void reloadListView(Model model)
        {
            this.lsvPics.BeginUpdate();
            this.lsvPics.Clear();
            if (model.CurrentDir != null)
            {
                foreach (var file in model.CurrentDir.Children)
                {
                    if (!file.IsDirectory)
                    {
                        ListViewItem item = new ListViewItem(file.Name);
                        item.ImageIndex = 0;
                        item.Tag = file;
                        this.lsvPics.Items.Add(item);
                    }
                }
            }
            this.lsvPics.EndUpdate();
        }

        private void mnOpen_Click(object sender, EventArgs e)
        {
            DlgMain openDlg = new DlgMain();
            if (openDlg.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    model.FS = logic.open(openDlg.User, openDlg.Pass, openDlg.Path);
                    reloadAll(model);
                }
                catch (InvalidArgumentException ex)
                {
                    MessageBox.Show("Open failed, maybe wrong user/pass. Please retry");
                }
            }
        }

        private void tvFolder_AfterSelect(object sender, TreeViewEventArgs e)
        {
            Path p = (Path)this.tvFolder.SelectedNode.Tag;
            if (p.IsDirectory)
            {
                model.CurrentDir = p;
                
                model.CurrentFile = p.FirstFile;
            }
            else
            {
                model.CurrentFile = p;
            }

            reloadViewer();
        }

        private void reloadViewer()
        {
            try
            {
                if (model.CurrentFile != null)
                {
                    byte[] all = logic.readFile(model);
                    Image img = utils.ImageUtils.byteArrayToImage(all);
                    this.picCurrent.Image = img;
                }
                else
                {
                    this.picCurrent.Image = null;
                }
                if (model.CurrentDir != null)
                {
                    reloadListView(model);
                }
            }
            catch (InvalidArgumentException e)
            {
                MessageBox.Show("bad file: " + model.CurrentFile.AbsolutePath + ". maybe been deleted"); 
            }
        }

        private void fileAdd_Click(object sender, EventArgs e)
        {
            OpenFileDialog dialog = new OpenFileDialog();
            dialog.Filter = "Image File|*.png;*.bmp;*.gif;*.jpg|All File|*.*";
            dialog.Multiselect = true;
            if (dialog.ShowDialog() == DialogResult.OK)
            {
                Thread t = new Thread(new System.Threading.ParameterizedThreadStart(addFile));
                t.Start(dialog.FileNames);
                sem.WaitOne();
            }
        }

        void addFile(object obj)
        {
            string[] files = (string[])obj;
            this.prgStatus.Maximum = files.Length;
            this.prgStatus.Value = 0;
            this.prgStatus.Visible = true;
            IFileSystem fs = model.FS;
            Path father = model.CurrentDir;
            sem.Release();
            operMutex.WaitOne();
            for (int i = 0; i < files.Length; i++)
            {
                this.lblStatus.Text = "adding " + (i + 1) + " of " + files.Length;
                this.lblStatus.Visible = true;
                logic.addFile(fs, father, files[i]);
                this.prgStatus.Value = i + 1;
                this.Invoke(new doReload(reloadAll), model);
            }
            this.prgStatus.Visible = false;
            this.lblStatus.Text = "";
            this.lblStatus.Visible = false;
            operMutex.ReleaseMutex();
        }

        private void tvFolder_AfterCollapse(object sender, TreeViewEventArgs e)
        {
            Path p = (Path)e.Node.Tag;
            p.Tag = false;
        }

        private void tvFolder_AfterExpand(object sender, TreeViewEventArgs e)
        {
            Path p = (Path)e.Node.Tag;
            p.Tag = true;
        }

        private void fileDelete_Click(object sender, EventArgs e)
        {
            doDelDir();
        }

        private void doDelDir()
        {
            if (model.CurrentDir == null || model.CurrentDir.Father == null)
            {
                MessageBox.Show("Can not delete Root Directory");
                return;
            }
            if (MessageBox.Show("Are you sure to delete " + model.CurrentDir.AbsolutePath + " and all sub files?", "Confirm", MessageBoxButtons.YesNo) != DialogResult.Yes)
            {
                return;
            }
            logic.deleteDir(model.FS, model.CurrentDir);
            model.CurrentDir = null;
            model.CurrentFile = null;
            reloadAll(model);
        }

        private void deleteDir(object obj)
        {
            IFileSystem fs = (IFileSystem)((Array)obj).GetValue(0);
            Path p = (Path)((Array)obj).GetValue(1);
            
            this.Invoke(new doReload(reloadAll), model);
        }

        private void lsvPics_SelectedIndexChanged(object sender, EventArgs e)
        {
            model.CurrentFile = (Path)this.lsvPics.SelectedItems[0].Tag;
            reloadViewer();
        }

        private void fileDelF_Click(object sender, EventArgs e)
        {
            doDelFile();
        }

        private void doDelFile()
        {
            if (model.CurrentFile == null)
            {
                return;
            }
            if (MessageBox.Show("Are you sure to delete " + model.CurrentFile.AbsolutePath + " ?", "Confirm", MessageBoxButtons.YesNo) != DialogResult.Yes)
            {
                return;
            }
            logic.deleteFile(model);
            reloadAll(model);
        }

        private void FrmMain_DragDrop(object sender, DragEventArgs e)
        {
            
        }

        private void FrmMain_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
                e.Effect = DragDropEffects.Link;
            else e.Effect = DragDropEffects.None;
        }

        private void mnImport_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog dlg = new FolderBrowserDialog();
            if (dlg.ShowDialog() == DialogResult.OK)
            {
                MessageBox.Show(dlg.SelectedPath);
            }
        }

        private void fileRotate_Click(object sender, EventArgs e)
        {
            Image img = this.picCurrent.Image;
            img.RotateFlip(RotateFlipType.Rotate90FlipNone);
            this.picCurrent.Image = img;
            
        }

        private void ctxDelDir_Click(object sender, EventArgs e)
        {
            doDelDir();
        }

        private void ctxDelFile_Click(object sender, EventArgs e)
        {
            doDelFile();
        }

        private void filePre_Click(object sender, EventArgs e)
        {
            doPreImage();
        }

        private void doPreImage()
        {
            logic.preImage(model);
            reloadAll(model);
        }

        private void fileNext_Click(object sender, EventArgs e)
        {
            doNextImage();
        }

        private void doNextImage()
        {
            if (model.FS == null)
            {
                return;
            }
            logic.nextImage(model);
            reloadAll(model);
        }

        private void picCurrent_Click(object sender, EventArgs e)
        {
            doNextImage();
        }
    }
}
